import store from '@/store/';
import axios from 'axios'
import router from '@/router/router'


class TokenManager {
  constructor() {
    // 防止多次刷新
    this.isRefreshing = false;
    // 存储等待刷新完成的请求
    this.refreshSubscribers = [];
  }

  // 获取本地存储中的 Token
  getAccessToken() {
    return store.getters.token
  }
  // 获取本地存储中的 Refresh Token
  getRefreshToken() {
    return store.state.user.refreshToken
  }

  /**
   * 解析JWT
   * @param { String } token
   * @returns { Object } - 解析后的 Payload 对象，包含以下字段:
   *          - exp {number}: 过期时间戳
   *          - iat {number}: 签发时间戳
   *          - jti {string}: JWT ID
   *          - user_id {string}: 用户ID
   */
  decodeJwt(token) {
    try {
      const base64Url = token.split('.')[1]; // 获取 Payload 部分
      const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); // 替换 URL 安全字符
      const jsonPayload = decodeURIComponent(
        atob(base64)
          .split('')
          .map((c) => `%${c.charCodeAt(0).toString(16).padStart(2, '0')}`)
          .join('')
      );
      return JSON.parse(jsonPayload); // 返回解析后的对象
    } catch (error) {
      console.error('JWT 解码失败:', error);
      return null;
    }
  }

  // 更新本地存储中的 Token
  setTokens(access_token, refresh_token='') {
    store.commit('SET_TOKEN', access_token)
    refresh_token && store.commit('SET_REFRESH_TOKEN', refresh_token)
  }

  /**
   * 检查 Token 是否即将过期
   * @param { String } token - JWT Token
   * @param { number } threshold - 阈值，默认为60秒
   */
  isTokenExpiringSoon(token, threshold = 60) {
    const payload = this.decodeJwt(token);
    if (!payload || !payload.exp) return true; // 没有 Token 或无效 Token
    const currentTime = Math.floor(Date.now() / 1000); // 当前时间戳
    return payload.exp - currentTime < threshold; // 剩余时间小于阈值
  }

  /**
   * Authorization 头部
   * @param {*} token 
   * @returns 
   */
  setAuthorization(token) {
    return `Bearer ${ token }`
  }

  /**
   * 刷新 Token
   * @param {*} config - axios 请求配置
   * @returns { Object } - 更新后的 axios 请求配置
   */
  async refreshToken(config) {
    const token = this.getAccessToken()
    if (token && this.isTokenExpiringSoon(token)) {
      if (!this.isRefreshing) {
        this.isRefreshing = true
        try {
          var { status, data } = await axios({
            baseURL: process.env.VUE_APP_BASE_API,
            withCredentials: true,
            url: '/system/user/token/refresh',
            method: 'post',
            data: {
              refresh: this.getRefreshToken(),
            }
          })
        } catch (error) {
          if (error.response) {
            data = error.response.data
            // 服务器返回了非 2xx 响应
            if (error.response.status === 401) {
              console.error('未授权，请重新登录');
              store.dispatch('FedLogOut')
              router.push({ path: '/login' })
              
              throw new Error(data.detail)
            }
            Message({
              message: data.detail,
              type: 'error'
            })
            throw new Error(data.detail)
          }
          throw new Error(data.detail)
        } finally {
          // 刷新完成，重置状态
          this.isRefreshing = false
          // 依次执行等待中的请求
          this.refreshSubscribers.forEach((callback) => callback());
          // 清空等待中的请求
          this.refreshSubscribers = [];
        }
        if (200 !== status) throw new Error(data.detail)
        this.setTokens(data.access)
        config.headers.Authorization = this.setAuthorization(data.access);
      } else {
        // 如果正在刷新，等待刷新完成
        return new Promise((resolve) => {
          this.refreshSubscribers.push(() => {
            config.headers.Authorization = this.setAuthorization(this.getAccessToken());
            resolve(config);
          });
        });
      }
    } else {
      config.headers.Authorization = this.setAuthorization(this.getAccessToken());
    }
    return config
  }
}

export const tokenManager = new TokenManager()